package itsm.isperp.module.service.bpm;

import itsm.isperp.framework.collection.tree.ITreeNode;
import itsm.isperp.framework.data.dialect.DialectFactory;
import itsm.isperp.framework.data.domain.DataRequest;
import itsm.isperp.framework.data.domain.PageResponse;
import itsm.isperp.framework.data.mybatis.domain.AbstractTreeNode;
import itsm.isperp.framework.service.BaseService;
import itsm.isperp.framework.utils.HibernateUUIDGenerator;
import itsm.isperp.framework.utils.Pair;
import itsm.isperp.framework.web.response.ResultMessage;
import itsm.isperp.module.entity.bpm.BpmProcessRelation;
import itsm.isperp.module.repository.bpm.BpmProcessRelationMapper;
import itsm.isperp.workflow.utils.BpmConst;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

/**
 * 
 * 
 * 
 * @author lizx
 * @date 2014-7-21
 * 
 */
@Service
public class BpmProcessRelationService extends BaseService<BpmProcessRelation> {

	@Resource
	public BpmProcessRelationMapper bpmProcessRelationMapper;

	@Override
	public BpmProcessRelationMapper getRepository() {
		return bpmProcessRelationMapper;
	}

	@Autowired
	protected JdbcTemplate jdbcTemplate;

	@Autowired
	protected BpmProcessSettingService bpmProcessSettingService;

	@Override
	public int saveOrUpdate(BpmProcessRelation entity) {
		this.saveOrUpdate(entity, null);
		return 1;
	}

	@Override
	public int saveOrUpdate(BpmProcessRelation entity, HttpServletRequest req) {

		// 设定from_id是否为根节点
		// 设定to_id是否为叶子节点
		boolean fromIsRoot = true, toIsLeaf = true;

		String sql = "("
				+ DialectFactory.getDialect().getLimitString(
						"SELECT 'false' AS r,'true' AS l FROM bpm_process_relation WHERE to_id='"
								+ entity.getFromId())
				+ "') UNION ALL ("
				+ DialectFactory.getDialect().getLimitString(
						"SELECT 'true' AS r,'false' AS l FROM bpm_process_relation WHERE from_id='"
								+ entity.getToId() + "'") + ")";

		List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
		int lSize = list.size();
		if (lSize == 1) {
			Map<String, Object> map = list.get(0);

			fromIsRoot = Boolean.valueOf(map.get("r").toString());
			toIsLeaf = Boolean.valueOf(map.get("l").toString());

		} else if (lSize == 2) {
			fromIsRoot = false;
			toIsLeaf = false;
		}

		entity.setFromIsRoot(fromIsRoot);
		entity.setToIsLeaf(toIsLeaf);
		entity.setId(HibernateUUIDGenerator.generate());
		Set<String> includeColumns = new HashSet<String>();
		int i = 0;
		if (req != null) {
			Enumeration<String> params = req.getParameterNames();

			for (; params.hasMoreElements();) {
				String v = params.nextElement();
				if (v.charAt(0) == '_') {
					v = v.substring(1);
				}
				includeColumns.add(v);
			}

			i = saveOrUpdateAndSpecific(entity, req, "from_is_root",
					"to_is_leaf");
		} else {
			i = saveOrUpdateButSpecific(entity, includeColumns);
		}

		String[] updates = new String[2];
		updates[0] = "UPDATE bpm_process_relation SET from_is_root=0 WHERE from_id='"
				+ entity.getToId() + "'";

		updates[1] = "UPDATE bpm_process_relation SET to_is_leaf=0 WHERE to_id='"
				+ entity.getFromId() + "'";

		jdbcTemplate.batchUpdate(updates);
		return i;
	}

	@Override
	public ResultMessage delete(String id) {
		Assert.notNull(id, "id不能为空");

		BpmProcessRelation entity = this.findOne(id);

		this.getRepository().deleteByClass(id, BpmProcessRelation.class);

		// 检查是否具有
		String sql = "("
				+ DialectFactory.getDialect().getLimitString(
						"SELECT 'false' AS r,'true' AS l FROM bpm_process_relation WHERE from_id='"
								+ entity.getFromId() + "'")
				+ ") UNION ALL ("
				+ DialectFactory.getDialect().getLimitString(
						"SELECT 'true' AS r,'false' AS l FROM bpm_process_relation WHERE from_id='"
								+ entity.getToId() + "'") + ")";

		boolean fromIsRoot = true, toIsLeaf = true;

		List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
		int lSize = list.size();
		if (lSize == 1) {
			Map<String, Object> map = list.get(0);

			fromIsRoot = Boolean.valueOf(map.get("r").toString());
			toIsLeaf = Boolean.valueOf(map.get("l").toString());

		} else if (lSize == 2) {
			fromIsRoot = false;
			toIsLeaf = false;
		}

		String sql1 = null, sql2 = null;

		// 如果不是根
		if (entity.isFromIsRoot() == false && fromIsRoot == false) {
			sql1 = "UPDATE bpm_process_relation SET to_is_leaf=1 WHERE to_id='"
					+ entity.getFromId() + "'";
		}

		if (entity.isToIsLeaf() == false && toIsLeaf == false) {
			sql2 = "UPDATE bpm_process_relation SET from_is_root=1 WHERE from_id='"
					+ entity.getToId() + "'";
		}

		if (sql1 != null || sql2 != null) {
			String[] updates;
			if (sql1 == null) {
				updates = new String[1];
				updates[0] = sql2;
			} else if (sql2 == null) {
				updates = new String[1];
				updates[0] = sql1;
			} else {
				updates = new String[2];
				updates[0] = sql1;
				updates[1] = sql2;
			}
			jdbcTemplate.batchUpdate(updates);
		}

		return ResultMessage.success();

	}

	public List<Map<String, Object>> listRelation(String id) {

		if (StringUtils.isEmpty(id)) {
			return null;
		}
		StringBuilder sb2 = new StringBuilder();

		sb2.append(" SELECT  to_id  AS relation_id ");
		sb2.append(" FROM bpm_process_relation ");
		sb2.append(" WHERE   from_id='" + id + "'");
		sb2.append(" UNION ALL ");

		sb2.append("SELECT  from_id AS relation_id ");
		sb2.append(" FROM bpm_process_relation ");
		sb2.append(" WHERE   to_id='" + id + "'");

		List<String> ids = this.jdbcTemplate.queryForList(sb2.toString(),
				String.class);

		StringBuilder sb = new StringBuilder();
		sb.append(" SELECT  *  FROM(  SELECT id,to_id  relation_id,creator,creator_name,create_date,from_type,to_type,'被关联'  relation_type_name");
		sb.append(" FROM bpm_process_relation ");
		sb.append(" WHERE   from_id='" + id + "'");
		sb.append(" UNION ALL ");

		sb.append("SELECT id,from_id AS relation_id,creator,creator_name,create_date,from_type,to_type,'来源' AS relation_type_name");
		sb.append(" FROM bpm_process_relation ");
		sb.append(" WHERE   to_id='" + id + "')t3");

		sb.append(" INNER JOIN( ");
		sb.append(BpmConst.getProcessListSql(null, id, ids, null, null));

		sb.append(")t ON t.BUSINESS_KEY_=t3.relation_id where t.KEY_=t3.from_type OR t.KEY_=t3.to_type");

		return this.jdbcTemplate.queryForList(sb.toString());

	}

	/**
	 * 列出
	 * 
	 * @param projectId
	 * @param processKey
	 * @param req
	 * @return
	 */
	public PageResponse<Map<String, Object>> listProcess(String projectId,
			String processKey, DataRequest req) {

		if(projectId.equals("undefined") || projectId.equals(""))
			projectId=null;
		StringBuilder sb = BpmConst.getProcessListSql(projectId, null, null,
				null, null);

		sb.append(" WHERE t2.KEY_='" + processKey + "' ");
	return 	this.bpmProcessRelationMapper.listProcess(" FROM ("+sb.toString()+") A WHERE 1=1", req).toPage();
	}

	public Pair<Boolean, Boolean> getRelation(String id) {
		// 检查是否具有
		String sql = "("
				+ DialectFactory.getDialect().getLimitString(
						" SELECT 'false' AS r,'true' AS l FROM bpm_process_relation WHERE to_id='"
								+ id + "'")
				+ ") UNION ALL ("
				+ DialectFactory.getDialect().getLimitString(
						"SELECT 'true' AS r,'false' AS l FROM bpm_process_relation WHERE from_id='"
								+ id + "'") + ")";

		boolean haveChild = false, haveParent = false;

		List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
		int lSize = list.size();
		if (lSize == 1) {
			Map<String, Object> map = list.get(0);

			haveChild = Boolean.valueOf(map.get("r").toString());
			haveParent = Boolean.valueOf(map.get("l").toString());

		} else if (lSize == 2) {
			haveParent = true;
			haveChild = true;
		}

		return new Pair<Boolean, Boolean>(haveChild, haveParent);

	}

	public List<ITreeNode> getRelationTree(String id, String rootId, int way) {
		List<ITreeNode> t = new ArrayList<ITreeNode>();

		if (StringUtils.isEmpty(id)) {
			AbstractTreeNode node = new AbstractTreeNode();
			node.setId(rootId);
			node.setName(way == 1 ? "向后追踪" : "向前追踪");
			node.setLeaf(false);

			t.add(node);

			return t;
		}
		List<Map<String, Object>> list = null;
		// 顺序
		if (way == 1) {
			String sql = "SELECT to_id AS id,to_type  AS relation_type,to_is_leaf  AS node_leaf , to_type AS ttype FROM bpm_process_relation WHERE from_id='"
					+ id + "'";

			list = jdbcTemplate.queryForList(sql);

		} else {

			String sql = "SELECT from_id  AS id,from_type AS relation_type,from_is_root AS node_leaf ,from_type AS ttype FROM bpm_process_relation WHERE to_id='"
					+ id + "'";
			list = jdbcTemplate.queryForList(sql);

		}

		Map<String, Map<String, Object>> data = new HashMap<String, Map<String, Object>>();

		String ids = parRelationData(data, list);

		List<Map<String, Object>> rDatas = getRelationEntity(ids);

		for (Map<String, Object> m : rDatas) {

			String bKey = m.get("BUSINESS_KEY_").toString();
			String title = m.get("title").toString();
			String processName = m.get("process_name").toString();
			String status = m.get("status").toString();

			int to_is_leaf = Integer.valueOf(data.get(bKey).get("node_leaf")
					.toString());

			AbstractTreeNode node = new AbstractTreeNode();
			node.setId(bKey);
			node.setName("[" + processName + "] - " + title + "(" + status
					+ ")");
			node.setLeaf(to_is_leaf == 1 ? true : false);

			node.setTreenodePath((String) (data.get(bKey).get("ttype")));
			t.add(node);
		}

		return t;
	}

	private String parRelationData(Map<String, Map<String, Object>> data,
			List<Map<String, Object>> ids) {

		StringBuilder idlist = new StringBuilder();
		if (ids != null && ids.size() > 0) {
			Map<String, Object> d = ids.get(0);
			idlist.append(" ").append("'").append(d.get("id").toString())
					.append("'");

			data.put(d.get("id").toString(), d);

			for (int j = 1; j < ids.size(); j++) {

				Map<String, Object> dd = ids.get(j);

				data.put(dd.get("id").toString(), dd);
				idlist.append(",'").append(dd.get("id").toString()).append("'");
			}
		}

		return idlist.toString();

	}

	private List<Map<String, Object>> getRelationEntity(String ids) {

		List<Map<String, Object>> list = bpmProcessSettingService
				.findProcessRelationList();
		StringBuilder sb = new StringBuilder();

		boolean hasUnionAll = false;
		for (int i = 0; i < list.size(); i++) {
			Object o = list.get(i).get("deployment_name");
			if (o == null || "null".equals(o.toString())) {
				continue;
			}

			if (hasUnionAll)
				sb.append(" UNION ALL ");

			hasUnionAll = true;

			BpmConst.appendProcessRelationSQL(null, ids, sb, list.get(i));
		}

		return jdbcTemplate.queryForList(sb.toString());

	}
}
